﻿#include "FITKGraphObjectSet.h"

// VTK
#include <vtkProperty.h>
#include <vtkUnstructuredGrid.h>

// Graph
#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActor.h"

// Data and manager
#include "FITK_Interface/FITKInterfaceModel/FITKModelSet.h"
#include "FITKSetSurfPolyProvider.h"

namespace Exchange
{
    FITKGraphObjectSet::FITKGraphObjectSet(AbaqusData::FITKDataCase* caseData, Interface::FITKModelSet* set, QVariant details)
        : FITKGraphObjectHighlightBase(caseData, set), m_instanceId(details.isValid() ? details.toInt() : -1)
    {
        // Return if the input is nullptr.
        if (!set)
        {
            return;
        }

        // Create set actors recursively.
        generateSetActor(set, m_instanceId);

        // Update the visibility.
        updateVisibility();
    }

    FITKGraphObjectSet::~FITKGraphObjectSet()
    {
        // Delete the copied dataset list.
        deleteVtkObjs(m_setGridList);
    }

    bool FITKGraphObjectSet::isRelatedTo(int dataObjId)
    {
        bool flag = this->Superclass::isRelatedTo(dataObjId);
        if (flag)
        {
            return true;
        }

        return m_subSetIds.contains(dataObjId);
    }

    void FITKGraphObjectSet::generateSetActor(Interface::FITKModelSet* set, int instanceId)
    {
        // Get the sub-set number.
        int nSubSet = set->getDataCount();
        if (nSubSet == 0)
        {
            // Get or generate set data.
            int modelId = -1;
            vtkUnstructuredGrid* setGrid = FITKSetSurfPolyProvider::getInstance()->getSetGridData(set->getDataObjectID(), modelId, m_instanceId);
            if (!setGrid)
            {
                return;
            }

            // Copy a new one.
            vtkUnstructuredGrid* grid = vtkUnstructuredGrid::New();
            grid->DeepCopy(setGrid);
            m_setGridList.push_back(grid);

            // Generate FITKGraphActor and add to data list.
            FITKGraphActor* actor = FITKGraphActor::New();
            actor->setGraphObject(this);
            actor->SetPickable(false);
            actor->setInputDataObject(grid);
            actor->SetVisibility(true);

            // Get set type.
            Interface::FITKModelEnum::FITKModelSetType type = set->getModelSetType();

            // Initialize properties.
            initActorProperties(actor, type);
            addActor(actor);

            // Add the actor to hash.
            m_actorModelIdHash.insert(actor, modelId);

            if (!m_modelIds.contains(modelId))
            {
                m_modelIds.push_back(modelId);
            }
        }
        else
        {
            // Create sub-set actors.
            for (int i = 0; i < nSubSet; i++)
            {
                // Save the sub-set id.
                m_subSetIds.push_back(set->getDataByIndex(i)->getDataObjectID());

                generateSetActor(set->getDataByIndex(i), instanceId);
            }
        }
    }

    void FITKGraphObjectSet::clearData()
    {
        // Save the graph widget.
        // Core::FITKAbstractGraphWidget* graphWidget = _graphWidget;

        // Remove from widget.
        removeFromGraphWidget();

        // Delete actors.
        for (vtkProp* prop : m_actorList)
        {
            prop->Delete();
        }

        m_actorList.clear();

        // Clear model info.
        m_modelVisibilityHash.clear();

        // Clear sub-set ids.
        m_subSetIds.clear();

        // Clear the actor model hash.
        m_actorModelIdHash.clear();

        // Delete the copied dataset list.
        deleteVtkObjs(m_setGridList);
    }

    void FITKGraphObjectSet::update(bool forceUpdate)
    {
        // There is no need to update the set graph object in normal case.
        if (forceUpdate)
        {
           
            Interface::FITKModelSet* set = dynamic_cast<Interface::FITKModelSet*>(_dataObj);
            if (!set)
            {
                return;
            }

            // Clear data first.
            clearData();

            // Create set actors recursively.
            generateSetActor(set, m_instanceId);
        }

        // Update the visibility only.
        updateVisibility();
    }

    void FITKGraphObjectSet::updateVisibility()
    {
        QHash<int, bool> modelVisibilityHash;

        // Save the visibility first, and check if the visbility has changed at the same time.
        bool hasChanged = false;
        for (int modelId : m_modelIds)
        {
            bool parentVisible = getParentDataVisibility(modelId);
            bool oldVisibility = m_modelVisibilityHash[modelId];
            if (parentVisible != oldVisibility)
            {
                hasChanged = true;
            }

            modelVisibilityHash.insert(modelId, parentVisible);
        }

        for (FITKGraphActor* fActor : m_actorModelIdHash.keys())
        {
            if (!fActor)
            {
                continue;
            }

            bool visibility = modelVisibilityHash[m_actorModelIdHash[fActor]];
            fActor->SetVisibility(visibility);
        }

        // Save the flags.
        m_modelVisibilityHash = modelVisibilityHash;
    }
}   // namespace Exchange